<template>
  <div>
    <el-upload
      :key="uk.upload"
      class="image-uploader"
      name="file"
      action="''"
      list-type="picture"
      :file-list="fileList"
      :show-file-list="false"
      :on-success="handleSuccess"
      :before-upload="beforeUpload"
      :http-request="handleUpload"
      :multiple="multiple"
      :disabled="disabled"
      :on-preview="handlePreview"
      :on-remove="handleRemove"
    >
      <!--      <i slot="default" class="el-icon-plus"/>
      <div slot="file" slot-scope="{file}">
        <span class="el-upload-list__item-actions">
          <span
            class="el-upload-list__item-preview"
            @click="handlePreview(file)"
          >
            <i class="el-icon-zoom-in"/>
          </span>
          <span
            v-if="!disabled"
            class="el-upload-list__item-delete"
            @click="handleDownload(file)"
          >
            <i class="el-icon-download"/>
          </span>
          <span
            v-if="!disabled"
            class="el-upload-list__item-delete"
            @click="handleRemove(file)"
          >
            <i class="el-icon-delete"/>
          </span>
        </span>
      </div>-->
      <img v-if="image && image.url" :src="image.url" class="image" :alt="size">
      <i v-else class="el-icon-plus image-uploader-icon"/>
      <div>{{ size }}</div>
    </el-upload>
    <el-dialog
      :key="uk.dialog"
      :title="title"
      :visible.sync="visibleDialog"
      :before-close="handleCancel"
      :modal="false"
      :modal-append-to-body="false"
      lock-scroll
      append-to-body
      width="700px"
      top="5vh"
    >
      <div style="height: 400px">
        <vue-cropper
          ref="cropper"
          :key="uk.corp"
          :img="img"
          :output-size="opts.outputSize"
          :output-type="opts.outputType"
          :info="opts.info"
          :can-scale="opts.canScale"
          :auto-crop="opts.autoCrop"
          :auto-crop-width="opts.autoCropWidth"
          :auto-crop-height="opts.autoCropHeight"
          :fixed="opts.fixed"
          :fixed-number="opts.fixedNumber"
          :full="opts.full"
          :fixed-box="opts.fixedBox"
          :can-move="opts.canMove"
          :can-move-box="opts.canMoveBox"
          :original="opts.original"
          :center-box="opts.centerBox"
          :high="opts.high"
          :info-true="opts.infoTrue"
          :max-img-size="opts.maxImgSize"
          :enlarge="opts.enlarge"
          :mode="opts.mode"
          @realTime="realTime"
          @imgLoad="imgLoad"
          @cropMoving="cropMoving"
        />
      </div>
      <div slot="footer" class="dialog-footer">
        <el-button @click="handleCancel">取消</el-button>
        <el-button type="primary" :loading="btnSaveLoading" @click="handleSave">上传</el-button>
      </div>
    </el-dialog>
  </div>
</template>

<script>
import {VueCropper} from 'vue-cropper'
import lodash from 'lodash'
import FileDTO from '@/api/entity/FileDTO'

export default {
  name: 'CropImageUpload',
  components: {VueCropper},
  model: {
    prop: 'image',
    event: 'change'
  },
  props: {
    width: { // 裁剪框宽度 ： width * enlarge = 上传图片宽度
      required: true,
      type: Number
    },
    height: { // 裁剪框高度 ： height * enlarge = 上传图片高度
      required: true,
      type: Number
    },
    enlarge: { // 裁剪框输出比例倍数
      type: Number,
      default: 1
    },
    upload: { // 上传方法
      required: true,
      type: Function
    },
    title: { // 弹窗标题
      type: String,
      default: '图片裁剪'
    },
    multiple: {
      type: Boolean,
      default: false
    },
    disabled: {
      type: Boolean,
      default: false
    },
    image: { // 外部传进来的图片，仅用于回显渲染
      type: Object,
      default() {
        return new FileDTO()
      }
    },
    cfg: {
      type: Object,
      default() {
        return {}
      }
    }
  },
  data() {
    return {
      uk: Object.freeze({
        upload: lodash.uniqueId('CropImageUpload_'),
        dialog: lodash.uniqueId('CropImageUpload_'),
        corp: lodash.uniqueId('CropImageUpload_')
      }),
      visibleDialog: false,
      btnSaveLoading: false,
      size: `${this.width * this.enlarge} x ${this.height * this.enlarge}`,
      srcFileName: '', // 原图文件名
      fileList: [this.image],
      previews: {},
      cropData: {},
      img: '', // 裁剪图片的地址, url 地址, base64, blob
      opts: Object.freeze(Object.assign(
        {
          outputSize: 1, // 裁剪生成图片的质量
          outputType: 'png', // 裁剪生成图片的格式	, jpg (jpg 需要传入jpeg), jpeg, png, webp
          info: true, // 裁剪框的大小信息
          canScale: true, // 裁剪框的大小信息
          autoCrop: true, // 是否默认生成截图框
          autoCropWidth: 200, // 默认生成截图框宽度, 容器的 80%, 只有自动截图开启 宽度高度才生效,
          autoCropHeight: 200, // 默认生成截图框高度	, 容器的 80%, 只有自动截图开启 宽度高度才生效,
          fixed: false, // 是否开启截图框宽高固定比例
          fixedNumber: [1, 1], // 截图框的宽高比例
          full: false, // 是否输出原图比例的截图
          fixedBox: true, // 固定截图框大小，不允许改变
          canMove: true, // 上传图片是否可以移动
          canMoveBox: true, // 截图框能否拖动
          original: false, // 上传图片按照原始比例渲染
          centerBox: true, // 截图框是否被限制在图片里面
          high: true, // 是否按照设备的dpr 输出等比例图片
          infoTrue: true, // true 为展示真实输出图片宽高 false 展示看到的截图框宽高
          maxImgSize: 5000, // 限制图片最大宽度和高度
          enlarge: 1, // 图片根据截图框输出比例倍数
          mode: 'contain' // 图片默认渲染方式	contain , cover, 100px, 100% auto
          // limitMinSize: [100, 120], //
        },
        this.cfg,
        {
          autoCropWidth: this.width,
          autoCropHeight: this.height,
          enlarge: this.enlarge
        }
      ))
    }
  },
  methods: {
    /**
     * 文件上传前校验文件格式和大小
     * @param file {File}
     */
    beforeUpload(file) {
      if (!file.type.startsWith('image/')) {
        this.$message.error('请选择有效图片!')
        return false
      }
      if (file.size / 1024 / 1024 > 10) {
        this.$message.error('选择图片大小不能超过 10M !')
        return false
      }
      this.srcFileName = file.name
      return true
    },
    handlePreview(file) {

    },
    handleRemove(file) {

    },
    handleDownload(file) {

    },
    /**
     * 文件选择成功
     * @param file
     * @param onSuccess
     * @param onError
     */
    handleUpload({file, onSuccess, onError}) {
      console.log(['file', file])
      const reader = new FileReader()
      reader.onload = e => {
        // console.log(e.target.result)
        if (typeof e.target.result === 'object') {
          // 把Array Buffer转化为blob 如果是base64不需要
          onSuccess(window.URL.createObjectURL(new Blob([e.target.result])))
        } else {
          onSuccess(e.target.result)
        }
      }
      reader.readAsDataURL(file) // 转化为base64
      // reader.readAsArrayBuffer(file) // 转化为blob

      // UploadService.uploadUser(file).then(result => result
      //   .dataFirst(row => onSuccess(row))
      //   .ifDataEmpty(() => onError('文件上传成功，但服务器未返回文件信息'))
      //   .ifFailure(() => onError(`文件上传失败:${result.message}`))
      // )
    },
    /**
     * 弹出裁剪插件
     */
    handleSuccess(file) {
      console.log(['file', file])
      this.img = file
      this.visibleDialog = true
    },
    // 取消裁剪
    handleCancel() {
      this.img = ''
      this.visibleDialog = false
    },
    handleSave() {
      this.btnSaveLoading = true
      this.$refs.cropper.getCropBlob(blob => {
        const file = new File([blob], `${this.srcFileName.replace(/.\w+$/)}.png`, {type: blob.type})
        // UploadService.uploadUser(file)
        this.upload(file)
          .then(result => result
            .dataFirst(row => {
              this.$refs.cropper.clearCrop()
              this.img = ''
              this.$emit('change', row)
              // this.$emit('update:image', row)
              this.visibleDialog = false
            })
            .ifDataEmpty(() => this.$message.error('文件上传成功，但服务器未返回文件信息'))
            .ifFailure(() => this.$message.error(`文件上传失败:${result.message}`))
          )
          .finally(() => (this.btnSaveLoading = false))
      })
    },
    // 实时预览函数
    realTime(data) {
      this.previews = data
    },
    // 图片加载的回调, 返回结果 success, error
    imgLoad(msg) {
      if (msg === 'error') {
        this.$message.error('图片裁剪组件初始化失败')
      }
    },
    // 截图框移动回调函数
    cropMoving(data) {
      this.cropData = data
    }
  }
}
</script>

<style scoped>
.image-uploader >>> .el-upload {
  border: 1px dashed #d9d9d9;
  border-radius: 6px;
  cursor: pointer;
  position: relative;
  overflow: hidden;
}

.image-uploader >>> .el-upload:hover {
  border-color: #409EFF;
}

.image-uploader-icon {
  font-size: 28px;
  color: #8c939d;
  width: 100px;
  height: 100px;
  line-height: 100px;
  text-align: center;
}

.image {
  width: 100px;
  height: 100px;
  display: block;
}
</style>
